/*	Compound.java
 *
 *	Copyright (c) Manateem Challenge Group, Zaia Group, and contributors 2010
 *
 *	This file is part of MSGToolSuite ('this project').
 *
 *	This project is free software: you can redistribute it and/or modify it
 *	under the terms of the GNU General Public License as published by the Free
 *	Software Foundation, either version 3 of the License, or (at your option)
 *	any later version.
 *
 *	This project is distributed in the hope that it will be useful, but WITHOUT
 *	ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 *	FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 *	more details.
 *
 *	You should have received a copy of the GNU General Public License along with
 *	this project. If not, see <http://www.gnu.org/licenses/>.
 */
package edu.bu.manateem.msg.model;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import edu.bu.manateem.msg.MSGConstants;
import edu.bu.manateem.msg.model.isotope.IsotopeDistribution;
import edu.bu.manateem.msg.model.isotope.Peak;

/**
 * A molecule is a molecule. 
 * A molecule is identified by its m/z and retention time.
 * @author gindiny
 *
 */
public class Compound
	implements Comparable<Compound>
{
	public Double retentionTime;
	public String name;
	public Double abundance;
	public Double relativeAbundance;
	Map<String,Integer> components;
	private int charge;
	private Peak peak;
	double mz;
	
	Map<Double,Double> profileInSearchWindow = new TreeMap<Double,Double>();
	Map<Double,Double> profileInComputedWindow = new TreeMap<Double,Double>();
	private List<IntensityValue> intensityValues =
		new ArrayList<IntensityValue>();
	private int numberOfScansInSummationWindow = 0;
	
	public Compound(Map<String,Integer> components,int charge,
		Double retentionTime,String name)
	{
		this.components = components;
		this.charge = charge;
		this.retentionTime = retentionTime;
		this.name = name;
		IsotopeDistribution dist =
			new IsotopeDistribution(this.components,this.charge);
		peak = dist.getPeaks().first();
		mz = peak.getMass();
		abundance = 0.0;
	}
	
	public void addIntensityValue(IntensityValue value)
	{
		intensityValues.add(value);
		
	}
	
	public void addToComputedProfile(Double retentionTime,Double value)
	{
		profileInComputedWindow.put(retentionTime,value);
	}
	
	public void addToSearchProfile(Double retentionTime,Double value)
	{
		profileInSearchWindow.put(retentionTime,value);
	}
	
	@Override
	public int compareTo(Compound o)
	{
		return name.compareTo(o.getName());
	}
	
	/**
	 * @return the abundance
	 */
	public Double getAbundance()
	{
		return abundance;
	}
	
	/**
	 * @return the charge
	 */
	public double getCharge()
	{
		return charge;
	}
	
	/**
	 * @return the components
	 */
	public Map<String,Integer> getComponents()
	{
		return components;
	}
	
	/**
	 * Returns the String representation of this
	 * Object's hashCode
	 * @return
	 */
	public String getId()
	{
		return Integer.toString(hashCode());
	}
	
	/**
	 * @return the intensityValues
	 */
	public List<IntensityValue> getIntensityValues()
	{
		return intensityValues;
	}
	
	public String getLabel()
	{
		StringBuilder sb = new StringBuilder();
		sb.append("name=");
		sb.append(name);
		sb.append("\\ncharge=");
		sb.append(charge);
		sb.append("\\nrelative abundance=");
		sb.append(relativeAbundance);
		sb.append("\\nretention time=");
		sb.append(retentionTime);
		sb.append("\\nm/z=");
		sb.append(mz);
		
		return sb.toString();
	}
	
	/**
	 * @return the mz
	 */
	public double getMz()
	{
		return mz;
	}
	
	/**
	 * @return the name
	 */
	public String getName()
	{
		return name;
	}
	
	/**
	 * @return the numberOfScansInSummationWindow
	 */
	public int getNumberOfScansInSummationWindow()
	{
		return numberOfScansInSummationWindow;
	}
	
	/**
	 * @return the p
	 */
	public double getP()
	{
		return peak.getP();
	}
	
	/**
	 * @return the profileInComputedWindow
	 */
	public Map<Double,Double> getProfileInComputedWindow()
	{
		return profileInComputedWindow;
	}
	
	/**
	 * @return the profileInSearchWindow
	 */
	public Map<Double,Double> getProfileInSearchWindow()
	{
		return profileInSearchWindow;
	}
	
	/**
	 * Return the abundance of this molecule
	 * @param useP take advantage of the p value associated
	 * with the monoisotopic peak. 
	 * @return
	 */
	public double getRelativeAbundance()
	{
		return relativeAbundance;
	}
	
	/**
	 * @return the retentionTime
	 */
	public Double getRetentionTime()
	{
		return retentionTime;
	}
	
	/**
	 * @param abundance the abundance to set
	 */
	public void setAbundance(Double abundance)
	{
		this.abundance = abundance;
	}
	
	/**
	 * @param mz the mz to set
	 */
	public void setMz(double mz)
	{
		this.mz = mz;
	}
	
	/**
	 * @param name the name to set
	 */
	public void setName(String name)
	{
		this.name = name;
	}
	
	/**
	 * @param numberOfScansInSummationWindow the numberOfScansInSummationWindow to set
	 */
	public void setNumberOfScansInSummationWindow(
		int numberOfScansInSummationWindow)
	{
		this.numberOfScansInSummationWindow = numberOfScansInSummationWindow;
	}
	
	/**
	 * @param relativeAbundance the relativeAbundance to set
	 */
	public void setRelativeAbundance(Double relativeAbundance)
	{
		this.relativeAbundance = relativeAbundance;
	}
	
	/**
	 * @param retentionTime the retentionTime to set
	 */
	public void setRetentionTime(Double retentionTime)
	{
		this.retentionTime = retentionTime;
	}
	
	@Override
	public String toString()
	{
		StringBuffer sb = new StringBuffer();
		sb.append("name=").append(name);
		sb.append(MSGConstants.TAB);
		sb.append("peak=").append(getMz());
		sb.append(MSGConstants.TAB);
		sb.append("p=").append(getP());
		sb.append(MSGConstants.TAB);
		sb.append("raw abundance=").append(abundance);
		sb.append("charge=").append(charge);
		sb.append(MSGConstants.TAB);
		sb.append("retention time=").append(retentionTime);
		return sb.toString();
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + charge;
		result = prime * result
				+ ((components == null) ? 0 : components.hashCode());
		result = prime * result
				+ ((retentionTime == null) ? 0 : retentionTime.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Compound other = (Compound) obj;
		if (charge != other.charge)
			return false;
		if (components == null) {
			if (other.components != null)
				return false;
		} else if (!components.equals(other.components))
			return false;
		if (retentionTime == null) {
			if (other.retentionTime != null)
				return false;
		} else if (!retentionTime.equals(other.retentionTime))
			return false;
		return true;
	}
	
}
